package com.xayy.core.antlr4.utils;

import cn.kawins.base.result.CheckResult;
import com.alibaba.fastjson.JSONObject;
import com.xayy.core.antlr4.enums.RuleResultEnum;
import com.xayy.core.antlr4.listener.GrammarErrorListener;
import com.xayy.core.antlr4.listener.LexicalErrorListener;
import com.xayy.core.antlr4.model.ErrorResult;
import com.xayy.core.antlr4.model.VisitorResult;
import com.xayy.core.antlr4.parsing.HealthEvaluateLexer;
import com.xayy.core.antlr4.parsing.HealthEvaluateParser;
import com.xayy.core.antlr4.visitor.HealthEvaluateVisitor;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Nie
 * @version V1.0
 * @date 2023/8/11 14:59
 */
@Slf4j
public class FunUtil {

    public static ErrorResult execute(String expression, HealthEvaluateVisitor visitor) {
        List<String> gramErrList = new ArrayList<>(0);
        ErrorResult.ErrorResultBuilder builder = ErrorResult.builder().expression(expression);
        HealthEvaluateLexer lexer = new HealthEvaluateLexer(CharStreams.fromString(expression));
        lexer.removeErrorListeners();
        LexicalErrorListener lexicalListener = new LexicalErrorListener();
        lexer.addErrorListener(lexicalListener);
        HealthEvaluateParser parser = new HealthEvaluateParser(new CommonTokenStream(lexer));
        parser.removeErrorListeners();
        GrammarErrorListener errorListener = new GrammarErrorListener();
        parser.addErrorListener(errorListener);
        ParseTree parseTree = parser.main();
        gramErrList.addAll(errorListener.getErrMessage());
        gramErrList.addAll(lexicalListener.getErrMessage());
        if (gramErrList.isEmpty()) {
            VisitorResult visit = visitor.visit(parseTree);
            builder.result(visit.getNumber());
            return builder.code(RuleResultEnum.SUCCESS.getCode()).build();
        } else {
            builder.code(RuleResultEnum.EXPRESS_ERR.getCode());
        }
        return builder.gramErrList(gramErrList).build();
    }

    /**
     * 校验语法
     *
     * @param satelliteId    卫星id
     * @param nodeId         节点id
     * @param evaluationTime 评估时刻
     * @param customParam    脚本
     * @return 结果日志
     */
    public static CheckResult<?> checkSyntax(Long satelliteId, Long nodeId, Date evaluationTime, String customParam) {
        ErrorResult execute =
                FunUtil.execute(customParam, new HealthEvaluateVisitor(satelliteId, nodeId, evaluationTime, true, false));
        if (!execute.isSuccess()) {
            int code = execute.getCode();
            List<String> gramErrList = execute.getGramErrList();
            return CheckResult.fail(code, gramErrList.toString());
        }
        return CheckResult.success();
    }

//
    public static void main(String[] args) throws Exception {
        String groovyScript = "import com.alibaba.fastjson.JSONObject \n" +
                "def execute(JSONObject data) {" +
                "println ('hello ' + data.name +' your age is ' + data.age)\n" +
                "return data.name" +
                "}";
        Object execute = getCondition(groovyScript, "execute", JSONObject.parseObject("{\"name\":\"xayy\",\"age\":18}"));

        System.out.println(execute);
    }

    private static <T> T getCondition(String groovyShell, String functionName, JSONObject vo) throws ScriptException, NoSuchMethodException {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("groovy");
        engine.eval(groovyShell);
        Invocable invocableEngine = (Invocable) engine;
        T result = (T) invocableEngine.invokeFunction(functionName, vo);
        return result;
    }

}
